package pinger

import (
	"fmt"
	"math"
	"net"
	"time"

	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
)

// ReplyInfo 应答信息
type ReplyInfo struct {
	From        net.IP
	ICMPType    int
	ICMPCode    int
	Seq         int
	RTT         time.Duration
	PayloadSize int
	Retry       int
	IsIPv6      bool
	Err         error
}

func (r *ReplyInfo) String() string {
	if r.Err != nil {
		return fmt.Sprintf("from %s: %s", r.From, r.Err.Error())
	}

	switch {
	case r.IsIPv6 && r.ICMPType == int(ipv6.ICMPTypeEchoReply) && r.ICMPCode == 0:
		fallthrough

	case !r.IsIPv6 && r.ICMPType == int(ipv4.ICMPTypeEchoReply) && r.ICMPCode == 0:
		if r.Retry > 0 {
			return fmt.Sprintf("from %s: payload=%dbytes seq=%d retry=%d rtt=%s", r.From, r.PayloadSize, r.Seq, r.Retry, r.RTT)
		} else {
			return fmt.Sprintf("from %s: payload=%dbytes seq=%d rtt=%s", r.From, r.PayloadSize, r.Seq, r.RTT)
		}

	default:
		var icmpType icmp.Type
		if r.IsIPv6 {
			icmpType = ipv6.ICMPType(r.ICMPType)
		} else {
			icmpType = ipv4.ICMPType(r.ICMPType)
		}
		return fmt.Sprintf("from %s: %s (type=%d, code=%d)", r.From, icmpType, r.ICMPType, r.ICMPCode)
	}
}

// summarizeRTTs
func summarizeRTTs(rtts []time.Duration) (min, avg, max, mdev time.Duration) {
	if rtts == nil || len(rtts) == 0 {
		return
	}

	min = rtts[0]
	var total, sumSquares time.Duration
	for _, rtt := range rtts {
		if rtt > max {
			max = rtt
		}
		if rtt <= min {
			min = rtt
		}
		total += rtt
	}

	rttsNumber := len(rtts)
	avg = total / time.Duration(rttsNumber)
	for _, rtt := range rtts {
		sumSquares += (rtt - avg) * (rtt - avg)
	}

	// mdev is the standard deviation of the round-trip times sent via this goPinger
	mdev = time.Duration(math.Sqrt(float64(sumSquares / time.Duration(rttsNumber))))

	return
}
